import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      // home: ScrollControllerTestRoute(),
      home: const MyHomePage(
        title: 'demo',
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: HeroAnimationRouteA(),
    );
  }
}
// Hero 指的是可以在路由(页面)之间“飞行”的 widget，简单来说 Hero 动画就是在路由切换时，有一个共享的widget 可以在新旧路由间切换。由于共享的 widget 在新旧路由页面上的位置、外观可能有所差异，所以在路由切换时会从旧路逐渐过渡到新路由中的指定位置，这样就会产生一个 Hero 动画。

// 你可能多次看到过 hero 动画。例如，一个路由中显示待售商品的缩略图列表，选择一个条目会将其跳转到一个新路由，新路由中包含该商品的详细信息和“购买”按钮。 在Flutter中将图片从一个路由“飞”到另一个路由称为hero动画，尽管相同的动作有时也称为 共享元素转换

// 假设有两个路由A和B，他们的内容交互如下：

// A：包含一个用户头像，圆形，点击后跳到B路由，可以查看大图。

// B：显示用户头像原图，矩形

class HeroAnimationRouteA extends StatelessWidget {
  const HeroAnimationRouteA({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment.topCenter,
      child: Column(
        children: <Widget>[
          InkWell(
            child: Hero(
              tag: "avatar", //唯一标记，前后两个路由页Hero的tag必须相同
              child: ClipOval(
                child: Image.network(
                    'http://uf-onegreen.52pictu.com/m-maps/m/a/world6.jpg',
                    width: 50.0),
              ),
            ),
            onTap: () {
              //打开B路由
              Navigator.push(context, PageRouteBuilder(
                pageBuilder: (
                  BuildContext context,
                  animation,
                  secondaryAnimation,
                ) {
                  return FadeTransition(
                    opacity: animation,
                    child: Scaffold(
                      appBar: AppBar(
                        title: const Text("原图"),
                      ),
                      body: HeroAnimationRouteB(),
                    ),
                  );
                },
              ));
            },
          ),
          const Padding(
            padding: EdgeInsets.only(top: 8.0),
            child: Text("点击头像"),
          )
        ],
      ),
    );
  }
}

class HeroAnimationRouteB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Hero(
        tag: "avatar", //唯一标记，前后两个路由页Hero的tag必须相同
        child: Image.network(
            'http://uf-onegreen.52pictu.com/m-maps/m/a/world6.jpg'),
      ),
    );
  }
}
// 实现 Hero 动画只需要用Hero组件将要共享的 widget 包装起来，并提供一个相同的 tag 即可，中间的过渡帧都是 Flutter 框架自动完成的。必须要注意， 前后路由页的共享Hero的 tag 必须是相同的，Flutter 框架内部正是通过 tag 来确定新旧路由页widget的对应关系的。

// Hero 动画的原理比较简单，Flutter 框架知道新旧路由页中共享元素的位置和大小，所以根据这两个端点，在动画执行过程中求出过渡时的插值（中间态）即可


// 先不使用Hero 动画，而是通过之前章节所学的知识来实现一下这个效果。

// class CustomHeroAnimation extends StatefulWidget {
//   const CustomHeroAnimation({Key? key}) : super(key: key);

//   @override
//   _CustomHeroAnimationState createState() => _CustomHeroAnimationState();
// }

// class _CustomHeroAnimationState extends State<CustomHeroAnimation>
//     with SingleTickerProviderStateMixin {
//   late AnimationController _controller;

//   bool _animating = false;
//   AnimationStatus? _lastAnimationStatus;
//   late Animation _animation;

//   //两个组件在Stack中的rect
//   Rect? child1Rect;
//   Rect? child2Rect;

//   @override
//   void initState() {
//     _controller =
//         AnimationController(vsync: this, duration: Duration(milliseconds: 200));
//     //应用curve
//     _animation = CurvedAnimation(
//       parent: _controller,
//       curve: Curves.easeIn,
//     );

//     _controller.addListener(() {
//       if (_controller.isCompleted || _controller.isDismissed) {
//         if (_animating) {
//           setState(() {
//             _animating = false;
//           });
//         }
//       } else {
//         _lastAnimationStatus = _controller.status;
//       }
//     });
//     super.initState();
//   }

//   @override
//   void dispose() {
//     _controller.dispose();
//     super.dispose();
//   }

//   @override
//   Widget build(BuildContext context) {
//     //小头像
//     final Widget child1 = wChild1();
//     //大头像
//     final Widget child2 = wChild2();

//     //是否展示小头像；只有在动画执行时、初始状态或者刚从大图变为小图时才应该显示小头像
//     bool showChild1 =
//         !_animating && _lastAnimationStatus != AnimationStatus.forward;

//     // 执行动画时的目标组件；如果是从小图变为大图，则目标组件是大图；反之则是小图
//     Widget targetWidget;
//     if (showChild1 || _controller.status == AnimationStatus.reverse) {
//       targetWidget = child1;
//     } else {
//       targetWidget = child2;
//     }

//     return LayoutBuilder(builder: (context, constraints) {
//       return SizedBox(
//         //我们让Stack 填满屏幕剩余空间
//         width: constraints.maxWidth,
//         height: constraints.maxHeight,
//         child: Stack(
//           alignment: AlignmentDirectional.topCenter,
//           children: [
//             if (showChild1)
//               // 布局中有定义
//               AfterLayout(
//                 //获取小图在Stack中占用的Rect信息
//                 callback: (value) => child1Rect = _getRect(value),
//                 child: child1,
//               ),
//             if (!showChild1)
//               AnimatedBuilder(
//                 animation: _animation,
//                 builder: (context, child) {
//                   //求出 rect 插值
//                   final rect = Rect.lerp(
//                     child1Rect,
//                     child2Rect,
//                     _animation.value,
//                   );
//                   // 通过 Positioned 设置组件大小和位置
//                   return Positioned.fromRect(rect: rect!, child: child!);
//                 },
//                 child: targetWidget,
//               ),
//             // 用于测量 child2 的大小，设置为全透明并且不能响应事件
//             IgnorePointer(
//               child: Center(
//                 child: Opacity(
//                   opacity: 0,
//                   child: AfterLayout(
//                     //获取大图在Stack中占用的Rect信息
//                     callback: (value) => child2Rect = _getRect(value),
//                     child: child2,
//                   ),
//                 ),
//               ),
//             ),
//           ],
//         ),
//       );
//     });
//   }

//   Widget wChild1() {
//     //点击后执行正向动画
//     return GestureDetector(
//       onTap: () {
//         setState(() {
//           _animating = true;
//           _controller.forward();
//         });
//       },
//       child: SizedBox(
//         width: 50,
//         child: ClipOval(child: Image.asset("imgs/avatar.png")),
//       ),
//     );
//   }

//   Widget wChild2() {
//     // 点击后执行反向动画
//     return GestureDetector(
//       onTap: () {
//         setState(() {
//           _animating = true;
//           _controller.reverse();
//         });
//       },
//       child: Image.asset("imgs/avatar.png", width: 400),
//     );
//   }

//   Rect _getRect(RenderAfterLayout renderAfterLayout) {
//     //我们需要获取的是AfterLayout子组件相对于Stack的Rect
//     return renderAfterLayout.localToGlobal(
//           Offset.zero,
//           //找到Stack对应的 RenderObject 对象
//           ancestor: context.findRenderObject(),
//         ) &
//         renderAfterLayout.size;
//   }
// }
